home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000 #2
/
Ham Radio 2000 - Volume 2.iso
/
HAMV2
/
TCP_IP
/
TNOS230S
/
BMUTIL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1997-08-18
|
51KB
|
2,057 lines
/*
* Simple mail user interface for KA9Q IP/TCP package.
* A.D. Barksdale Garbee II, aka Bdale, N3EUA
* Copyright 1986 Bdale Garbee, All Rights Reserved.
* Permission granted for non-commercial copying and use, provided
* this notice is retained.
* Copyright 1987 1988 Dave Trulli NN2Z, All Rights Reserved.
* Permission granted for non-commercial copying and use, provided
* this notice is retained.
*
* Ported to NOS at 900120 by Anders Klemets SM0RGV.
*
* Userlogging, 'RM' and 'KM' implementation,
* more-prompts for all types
* 920307 and later, by Johan. K. Reinalda, WG7J/PA3DIS
* 920719 and later, by Brian A. Lantz, KO4KS
*/
#include "global.h"
#include "ctype.h"
#include "commands.h"
#include "files.h"
#ifdef MSDOS
#include <io.h>
#else
#include <time.h>
#endif
#include "ftpserv.h"
#include "smtp.h"
#include "proc.h"
#include "usock.h"
#include "telnet.h"
#include "mailbox.h"
#include "bm.h"
#include "color.h"
#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: bmutil.c,v 1.40 1997/08/19 01:19:22 root Exp root $";
#endif
#ifndef UNIX
#define SETVBUF
#else
#include <sys/stat.h>
#endif
#ifdef SETVBUF
#define MYBUF 1024
#endif
static void readareas (const char *name);
void freeareas (void);
static int is_area2 (const char *name);
extern int mbx_data (struct mbx * m, struct list * cclist, char *extra, int returnreceipt);
extern int dombroute (int argc, char *argv[], void *p);
extern void updateCtl (const char *who, struct let * info);
extern int makeBBSbid (char *bid, int bidlen, char *line);
#ifdef SAMCALLB
extern char *cb_lookname (char *);
#endif
#ifdef MAILCMDS
char Badmsg[] = "Invalid Message number %d\n";
static char Badrange[] = "Invalid Message range '%d - %d'\n";
char Nomail[] = "No messages\n";
static char NoMsgs[] = "No message numbers given\n";
static char anymore[] = "More(N=no)? ";
static int readnotes (struct mbx * m, int already);
static long isnewmail (struct mbx * m);
static int initnotes (struct mbx * m);
static void noteheader (struct mbx * m, int usebid);
static void close_notes (int a, void *b, void *c);
static void mfclose (struct mbx * m);
#endif
int lockit (struct mbx * m);
extern char *nntp_name_expansion (char *name);
static void dodeleting (struct mbx * m, int msg);
static int is_area (const char *name, const char *listfile);
char *mblookname (struct mbx * m, char *str);
void notifynewmail (struct mbx * m);
void backEmUp (int len);
#ifdef SAMCALLB
void leadingCaps (char *str, int others);
#endif
static char logdelmsg[] = "Msg %d in area '%s' made %s by '%s'";
const char hitEnter[] = "Hit enter to continue";
extern int MBnoReturnReceipt;
FILE *subdir_fopen (char *name, const char *mode);
FILE *
subdir_fopen (char *name, const char *mode)
{
FILE *fp;
char *cp;
#undef ENOENT
#define ENOENT 2
if ((fp = fopen (name, mode)) != (FILE *) 0)
return fp;
if ((errno == ENOENT) && !strchr (mode, 'r')) {
cp = &name[1];
while ((cp = strpbrk (cp, "/\\")) != (char *) 0) {
*cp = 0;
if (access (name, 0))
if (mkdir (name, 0777))
return ((FILE *) 0);
*cp++ = '/';
}
fp = fopen (name, mode);
return fp; /* NULL if STILL not opened */
}
return ((FILE *) 0);
}
#ifdef MAILBOX
#ifdef MAILCMDS
static int
initnotes (struct mbx *m)
{
char buf[256];
int wasit = 0;
#ifdef USERLOG
register struct let *cmsg;
int i;
#endif
if (m->mfile != NULLFILE) {
(void) fclose (m->mfile);
wasit = m->nmsgs;
}
sprintf (buf, "%s/%s.txt", Mailspool, m->area);
if ((m->mfile = subdir_fopen (buf, READ_TEXT)) == NULLFILE)
return 0;
m->mboxsize = (long) filelength (fileno (m->mfile));
if (!(m->sid & MBX_SID) && !stricmp (m->area, m->name)) /* our private mail area */
m->mysize = m->mboxsize;
m->nmsgs = 0;
m->change &= CHG_SPECIAL;
m->newmsgs = 0;
m->newmsgsonentry = 0;
m->anyread = 0;
/* Allocate space for reading messages */
(void) readnotes (m, wasit);
#ifdef USERLOG
m->current = 0; /*reset it*/
if (m->nmsgs)
for (cmsg = &m->mbox[1], i = 1; i <= m->nmsgs; i++, cmsg++)
if ((cmsg->status & BM_READ) == 0) {
m->current = i; /* first new message */
break;
}
/* start at one if no new messages */
if ((m->current == 0) && m->nmsgs)
m->current++;
#endif
return 0;
}
/* readnotes assumes that ifile is pointing to the first
* message that needs to be read. For initial reads of a
* notesfile, this will be the beginning of the file. For
* rereads when new mail arrives, it will be the first new
* message.
*/
static int
readnotes (register struct mbx *m, int already)
{
register FILE *fp;
char mailbox[128];
long size;
register int i, isit;
register struct let *cmsg;
struct let *new;
m->newmsgs = m->hmsgs = 0;
sprintf (mailbox, "%s/control/%s.ctl", Mailspool, m->area);
if ((fp = subdir_fopen (mailbox, READ_BINARY)) != NULLFILE) {
#if !defined(TNOS_68K)
m->stdoutbuf = mallocw (MYBUF);
(void) setvbuf (fp, m->stdoutbuf, _IOFBF, MYBUF);
#endif
size = (long) filelength (fileno (fp));
new = (struct let *) mallocw ((unsigned long) size + sizeof (struct let));
(void) fread (&new[1], (unsigned) size, 1, fp);
(void) fclose (fp);
if (already && !strcmp (m->area, m->name))
memcpy (new, m->mbox, (unsigned) (already + 1) * sizeof (struct let));
#if !defined(TNOS_68K)
free (m->stdoutbuf);
m->stdoutbuf = 0;
#endif
free (m->mbox);
m->mbox = new;
m->nmsgs = (int) (size / (long) sizeof (struct let));
isit = issysarea (m->area);
for (cmsg = &m->mbox[1], i = 1; i <= m->nmsgs; i++, cmsg++)
if (isit) {
if ((cmsg->bid > m->lastread) && !(cmsg->status & BM_DELETE))
m->newmsgs++;
else
cmsg->status |= BM_READ;
if (cmsg->status & BM_ONHOLD)
m->hmsgs++;
} else {
if (!(cmsg->status & BM_READ))
m->newmsgs++;
if (cmsg->status & BM_ONHOLD)
m->hmsgs++;
}
} else
m->nmsgs = 0;
m->newmsgsonentry = m->newmsgs;
return 0;
}
/* Display the header to a listing */
static void
noteheader (struct mbx *m, int usebid)
{
char *area, *cp;
area = strdup (m->area);
while ((cp = strchr (area, '/')) != NULLCHAR)
*cp = '.';
bbscolorcls (m);
tputs ("\nMail area: ");
bbscolorchange (m, "09");
tputs (area);
bbscolorchange (m, "0B");
tprintf (" %d ", m->nmsgs);
bbscolorchange (m, "0F");
tprintf ("message%s - ", m->nmsgs == 1 ? " " : "s ");
bbscolorchange (m, "0B");
tprintf ("%d ", m->newmsgs);
bbscolorchange (m, "0F");
tprintf ("new\n\nStat # TO FROM %s SUBJECT\n", (usebid) ? "MESSAGE ID " : " DATE SIZE");
free (area);
}
/* list headers of a notesfile a message */
/* Rearranged display - WG7J */
int
dolistnotes (int argc, char *argv[], void *p)
{
struct mbx *m;
struct let *cmsg;
char *cp, *s;
char smtp_date[SLINELEN], smtp_from[SLINELEN];
char smtp_subject[SLINELEN], tstring[LINELEN], type;
char smtp_to[SLINELEN], smtp_bid[30];
int start, stop;
long size;
int c, usemore = 0, lin;
int usebid = 0;
int headerseen = 0;
#if 0
char *area;
#endif
#ifdef USERLOG
long msgid;
#endif
m = (struct mbx *) p;
/*If this user doesn't have read-permissions,
*we're not going to let him list anything - WG7J */
if (m->privs & NO_READCMD) {
tputs (Noperm);
return 0;
}
if (m->mfile == NULLFILE) {
if (!(m->privs & ALL_AREAS))
tputs (Nomail);
return 0;
}
if (m->stype == 'B') {
usebid = 1;
m->stype = ' ';
}
if (m->stype == '$')
usebid = 1;
if ((m->stype == 'S' || m->stype == '$' || m->stype == '>' || m->stype == '<') && argc == 1) {
tputs ("Search criterium needed!\n");
return 0;
}
if ((lin = m->morerows) != 0)
usemore = 1; /* Display More prompt */
#if 0
noteheader (m, usebid);
#endif
stop = m->nmsgs;
if (m->stype == 'L') { /* LL (List Latest) command */
if (argc > 1)
start = stop - atoi (argv[1]) + 1;
else
start = stop;
if (start < 1)
start = 1;
} else {
if ((m->stype == 'A') || (m->stype == '>') ||
(m->stype == '<') || (m->stype == 'S') ||
(m->stype == '$') || (m->stype == 'H') ||
(m->stype == 'M')) {
start = 1;
stop = m->nmsgs;
} else {
if (argc > 1)
start = atoi (argv[1]);
else
#ifdef USERLOG
#if 0
start = m->nmsgs - m->newmsgsonentry + 1;
#else
start = (m->newmsgsonentry) ? m->current : (m->nmsgs - m->newmsgsonentry + 1);
#endif
#else
start = 1;
#endif
if (argc > 2)
stop = atoi (argv[2]);
}
}
if (stop > m->nmsgs)
stop = m->nmsgs;
if (start < 1 || start > stop) {
if (!(m->privs & ALL_AREAS)) {
if ((m->stype == ' ') || (m->stype == 'M'))
tputs ("No new mail.\n");
else
tputs ("Invalid range.\n");
}
return 0;
}
if (m->sid & MBX_HTTP)
tprintf ("<PRE>\n");
for (cmsg = &m->mbox[start]; start <= stop; start++, cmsg++) {
*smtp_date = '\0';
*smtp_from = '\0';
*smtp_subject = '\0';
*smtp_to = '\0';
*smtp_bid = '\0';
type = ' ';
fseek (m->mfile, cmsg->start, 0);
size = cmsg->size;
/* Be a little less selfish - WG7J */
kwait (NULL);
#ifdef USERLOG
/* We need to get the id from the last message listed !
* m->mbox[i].start (ie cmsg->start) points to the 'From ' line
* next are the 'Received....' and 'ID...' lines
* These are thes line added by our smtp server.
* following the 'AA' is the number that we want ! - WG7J
*/
#if 0
if (start == stop) {
#endif
/*The 'From ' line*/
(void) fgets (tstring, sizeof (tstring), m->mfile);
size -= (long) strlen (tstring);
/*The 'Received' line*/
(void) fgets (tstring, sizeof (tstring), m->mfile);
size -= (long) strlen (tstring);
/*The 'ID' line*/
(void) fgets (tstring, sizeof (tstring), m->mfile);
size -= (long) strlen (tstring);
/* find id number */
#ifdef nope
if ((cmsg->bid > m->lastread) && (cmsg->bid > m->newlastread))
m->newlastread = cmsg->bid;
#else
if ((cp = strstr (tstring, "AA")) != NULLCHAR) {
/*what follows is the message-number*/
msgid = atol (cp + 2);
if ((msgid > m->lastread) && (msgid > m->newlastread))
m->newlastread = msgid;
}
#endif
#if 0
}
#endif
#endif
while (size > 0 && fgets (tstring, sizeof (tstring), m->mfile) != NULLCHAR) {
kwait (NULL);
if (*tstring == '\n') /* end of header */
break;
size -= (long) strlen (tstring);
rip (tstring);
/* handle continuation later */
if (*tstring == ' ' || *tstring == '\t')
continue;
switch (htype (tstring)) {
case FROM:
cp = getaddress (tstring, 0);
strncpy (smtp_from, cp != NULLCHAR ? cp : "", 8);
if ((cp = strchr (smtp_from, '@')) != NULLCHAR)
*cp = '\0'; /* get rid of @-host or @-bbs field */
break;
case SUBJECT:
trimright (tstring);
cp = skipwhite (&tstring[9]);
strncpy (smtp_subject, cp, 35);
break;
case MSGID:
strncpy (smtp_bid, &tstring[12], 29);
break;
case DATE:
if ((cp = strchr (tstring, ',')) == NULLCHAR)
cp = &tstring[6];
else
cp++;
/* skip spaces */
while (*cp == ' ')
cp++;
if (strlen (cp) < 17)
break; /* not a valid length */
s = smtp_date;
/* copy day */
if (atoi (cp) < 10 && *cp != '0')
*s++ = ' ';
else
*s++ = *cp++;
*s++ = *cp++;
*s++ = ' ';
*s = '\0';
while (*cp == ' ')
cp++;
strncat (s, cp, 3); /* copy month */
#ifdef use_time
cp += 3;
while (*cp == ' ')
cp++;
/* skip year */
while (isdigit (*cp))
cp++;
/* copy time */
strncat (s, cp, 6); /* space hour : min */
#endif
break;
case BBSTYPE:
type = tstring[16];
break;
case TO:
strncpy (smtp_to, &tstring[4], 13);
break;
case NOHEADER:
default:
break;
}
}
if ((m->stype == 'M') && (cmsg->status & BM_READ))
continue;
if (m->stype == ' ' || m->stype == 'L' || m->stype == 'M' ||
m->stype == 'A' || (type == m->stype && m->stype != ' ') ||
((m->stype == 'H') && (cmsg->status & BM_ONHOLD)) ||
((m->stype == 'S') && (strstr (strlwr (smtp_subject), argv[1]) != NULLCHAR)) ||
((m->stype == '<') && (strstr (strlwr (smtp_from), argv[1]) != NULLCHAR)) ||
((m->stype == '$') && (strstr (strlwr (smtp_bid), argv[1]) != NULLCHAR)) ||
((m->stype == '>') && (strstr (strlwr (smtp_to), argv[1]) != NULLCHAR))) {
lin--;
if ((cmsg->status & BM_DELETE) && !(m->privs & SYSOP_CMD))
strcpy (smtp_subject, "[DELETED]");
if (!(headerseen++ % 50))
noteheader (m, usebid);
bbscolorchange (m, "07");
if (m->sid & MBX_HTTP)
tprintf ("<A HREF=\"/bbs/message/%s/%d.html\">", m->area, start);
tprintf ("%c%c%c%c%3d ", (start == m->current ? '>' : ' '),
(cmsg->status & BM_DELETE ? 'D' :
cmsg->status & BM_ONHOLD ? 'H' : ' '),
(cmsg->status & BM_READ ? 'Y' : 'N'),
(cmsg->status & BM_PERMANENT) ? 'P' : ' ',
start);
bbscolorchange (m, "0E");
tprintf ("%13.13s ", smtp_to);
bbscolorchange (m, "0C");
tprintf ("%8.8s ", smtp_from);
bbscolorchange (m, "07");
if (usebid) {
char *tmpbid, *bidptr = smtp_bid;
if (*bidptr == '<')
bidptr++;
if ((tmpbid = strchr (bidptr, '@')) != NULLCHAR) {
if (strstr (tmpbid, ".bbs") || strcmp (tmpbid, "@hamradio"))
*tmpbid++ = 0;
else {
*tmpbid = '_';
tmpbid = strchr (tmpbid, '.');
if (tmpbid)
*tmpbid = 0;
}
}
(void) strupr (bidptr);
tprintf ("%-13.13s ", bidptr);
} else {
tprintf ("%-7.7s ", smtp_date);
tprintf ("%5ld ", cmsg->size);
}
bbscolorchange (m, "0E");
tprintf ("%.34s\n", smtp_subject);
if (m->sid & MBX_HTTP)
tprintf ("</A>");
#ifdef STATS_AREA
STATS_addarea (0, 1, m->area);
#endif
}
/* More prompting added - WG7J */
if (usemore && lin == 0) {
if (m->type == TELNET || m->type == TIP)
c = tkeywait ("--More--", 0, m->linemode);
else /* For AX.25 and NET/ROM connects - WG7J */
c = mykeywait (anymore, m);
#ifdef MBXTDISC
start_timer (&m->tdisc);
#endif
if (c == -1 || c == 'q' || c == 'Q' || c == 'n' || c == 'N')
break;
#ifdef TNOS_68K
if (c == '\l' || c == '\r')
#else
if (c == '\n' || c == '\r')
#endif
lin = 1;
else
lin = m->morerows;
}
}
if (m->sid & MBX_HTTP)
tprintf ("</PRE>\n");
return 0;
}
/* save msg on stream - if noheader set don't output the header */
int
msgtofile (
struct mbx *m,
int msg,
FILE * tfile, /* already open for write */
int noheader,
int numbered
) {
char tstring[LINELEN];
long size;
int lineno = 0;
if (m->mfile == NULLFILE) {
tputs (Nomail);
return -1;
}
fseek (m->mfile, m->mbox[msg].start, 0);
size = m->mbox[msg].size;
if (noheader) {
/* skip header */
while (size > 0 && fgets (tstring, sizeof (tstring) - 1, m->mfile) != NULLCHAR) {
size -= (long) strlen (tstring);
kwait (NULL);
if (*tstring == '\n')
break;
}
}
while (size > 0 && fgets (tstring, sizeof (tstring) - 1, m->mfile)
!= NULLCHAR) {
kwait (NULL);
size -= (long) strlen (tstring);
if (numbered)
fprintf (tfile, "%02d) ", ++lineno);
fputs (tstring, tfile);
if (ferror (tfile)) {
tputs ("Error writing mail file\n");
return -1;
}
}
return 0;
}
static void
dodeleting (struct mbx *m, int msg)
{
switch (m->stype) {
case 'U':
m->mbox[msg].status &= ~BM_DELETE;
tprintf ("Msg %d Un-Killed.\n", msg);
break;
case 'A':
m->mbox[msg].status &= ~BM_ONHOLD;
tprintf ("Msg %d Available.\n", msg);
log (m->user, logdelmsg, msg, m->area, "available", m->name);
break;
case 'H':
m->mbox[msg].status |= BM_ONHOLD;
tprintf ("Msg %d Held.\n", msg);
log (m->user, logdelmsg, msg, m->area, "held", m->name);
break;
case 'T':
m->mbox[msg].status &= ~BM_PERMANENT;
tprintf ("Msg %d Temporary.\n", msg);
log (m->user, logdelmsg, msg, m->area, "temporary", m->name);
break;
case 'P':
m->mbox[msg].status |= BM_PERMANENT;
tprintf ("Msg %d Permanent.\n", msg);
log (m->user, logdelmsg, msg, m->area, "permanent", m->name);
break;
default:
if (m->mbox[msg].status & BM_PERMANENT)
tprintf ("Can't kill message %d - Message is permanent!\n", msg);
else {
m->mbox[msg].status |= BM_DELETE;
m->mbox[msg].status &= ~BM_ONHOLD;
tprintf ("Msg %d Killed.\n", msg);
if (!issysarea (m->area))
m->change |= CHG_DELETE;
}
break;
}
statusCtl (m->area, "ctl", &m->mbox[msg], msg, 0);
}
/* dodelmsg - delete message in current notesfile */
/* Modified to allow the 'KM' command. 920307 - WG7J */
/* also handles holsing/releasing messages - KO4KS */
int
dodelmsg (int argc, char *argv[], void *p)
{
struct mbx *m;
int msg = 0, i = 0;
char *myargv[NARG];
int myargc = 0;
int maxmsg;
struct let *cmsg;
char *tmpbuf;
int start, end;
m = (struct mbx *) p;
/* If this user doesn't have read-permissions,
* we're not going to let him kill/hold anything;
* allow anyone to kill/hold messages in areas
* who's names start with 'nts' - WG7J
*/
/* Check if we have permission to delete others mail */
if ((m->privs & NO_READCMD) || (m->privs & NO_SENDCMD) ||
(!(m->privs & FTP_WRITE) &&
stricmp (m->area, m->name) &&
strnicmp (m->area, "nts", 3))) {
tputs (Noperm);
return 0;
}
if ((m->stype == 'A' || m->stype == 'H' || m->stype == 'P' || m->stype == 'T') && !(m->privs & SYSOP_CMD)) {
tputs (Noperm);
return 0;
}
if (m->stype == 'S') {
if (argc > 2) {
myargc = msg = atoi (argv[1]);
i = atoi (argv[2]);
}
if ((argc < 3) || !msg || !i)
tputs (NoMsgs);
else {
for (; myargc <= i; myargc++) {
m->mbox[myargc].status |= BM_DELETE;
m->mbox[myargc].status &= ~BM_ONHOLD;
statusCtl (m->area, "ctl", &m->mbox[myargc], myargc, 0);
}
if (!issysarea (m->area))
m->change |= CHG_DELETE;
tprintf ("Msgs %d to %d Killed.\n", msg, i);
}
return 0;
}
if (m->mfile == NULLFILE) {
tputs (Nomail);
return 0;
}
/*If this is the KM command, setup myargv[]
*to contain up to NARG message numbers - WG7J
*/
if (m->stype == 'M') {
myargc = 1;
/* scan all messsages to find read ones */
maxmsg = min (m->nmsgs, NARG - 1);
for (i = 1; i <= maxmsg; i++) {
cmsg = &m->mbox[i];
if (cmsg->status & BM_READ) { /*found a read msg!*/
tmpbuf = mallocw (18); /*allocate space for the new argument*/
myargv[myargc++] = itoa (i, tmpbuf, 10);
}
}
if (myargc == 1) {
tputs (NoMsgs);
return 0;
}
argc = myargc;
} else {
if (argc == 1) {
if (m->stype != 'A') {
msg = m->current;
dodeleting (m, msg);
return 0;
} else {
for (i = 1; i <= m->nmsgs; i++) {
cmsg = &m->mbox[i];
if (cmsg->status & BM_ONHOLD) {
cmsg->status &= ~BM_ONHOLD;
statusCtl (m->area, "ctl", cmsg, i, 0);
}
}
tputs ("All Messages Available.\n");
return 0;
}
}
/*simply point to the old arguments*/
for (i = 1; i < argc; i++)
myargv[i] = argv[i];
}
/* See if x - y format was used and use a for i = x to y loop */
if (argc > 2 && myargv[2][0] == '-') { /*lint !e644 */
start = atoi (myargv[1]);
if (myargv[2][1])
end = atoi (&myargv[2][1]);
else
end = atoi (myargv[3]);
if (start < 0 || start > m->nmsgs || end < 0 || end > m->nmsgs)
tprintf (Badrange, start, end);
else
for (i = start; i <= end; i++) {
msg = i;
dodeleting (m, msg);
} /* endfor */
} else
for (i = 1; i < argc; ++i) {
tmpbuf = strchr (myargv[i], '-'); /* N5KNX: allow from-to msg specification */
msg = atoi (myargv[i]);
if (tmpbuf == NULLCHAR)
maxmsg = msg;
else
maxmsg = atoi (++tmpbuf);
if (maxmsg < msg) {
tprintf (Badmsg, myargv[i]);
continue;
}
for (; msg <= maxmsg; msg++) {
if (msg < 0 || msg > m->nmsgs) {
tprintf (Badmsg, msg);
continue;
}
dodeleting (m, msg);
}
}
/* If this was 'KM'
* free the memory allocated for myargv[] - WG7J
*/
if (m->stype == 'M') {
for (i = 1; i < argc; i++)
free (myargv[i]);
}
return 0;
}
struct clparms {
int nostatus, nodelete;
long *hostsize;
long _hostsize;
char name[20]; /* Name of remote station */
char area[64]; /* name of current mail area */
FILE *mfile; /* mail data file pointer */
struct let *mbox;
int nmsgs; /* number of messages in this mail box */
int isbbs;
};
static void
close_notes (int a OPTIONAL, void *b, void *c OPTIONAL)
{
struct clparms *cl;
struct let *cmsg;
char *line;
char tstring[LINELEN], buf[256];
char buf2[256];
long size, diff;
FILE *nfile;
int i, nextisBID, numwritten = 0;
int foundstatus, firstIDline;
#if 0
char *cp;
long msgid;
#endif
cl = (struct clparms *) b;
line = tstring;
sprintf (buf, "%s/control/%s.ctl", Mailspool, cl->area);
(void) remove (buf);
(void) fclose (cl->mfile);
sprintf (buf, "%s/%s.txt", Mailspool, cl->area);
sprintf (buf2, "%s/%s.bak", Mailspool, cl->area);
(void) remove (buf2); /* delete it here, just in case! */
(void) rename (buf, buf2);
if ((cl->mfile = subdir_fopen (buf2, READ_TEXT)) == NULLFILE) {
rmlock (Mailspool, cl->area);
free (cl);
return;
}
if ((nfile = subdir_fopen (buf, WRITE_TEXT)) == NULLFILE) {
(void) fclose (cl->mfile);
rmlock (Mailspool, cl->area);
free (cl);
return;
}
/* copy tmp file back to notes file */
for (cmsg = &cl->mbox[1], i = 1; i <= cl->nmsgs; i++, cmsg++) {
fseek (cl->mfile, cmsg->start, 0);
kwait (NULL);
cmsg->start = ftell (nfile);
size = cmsg->size;
diff = 0;
foundstatus = 0;
/* It is not possible to delete messages if nodelete is set */
if ((cmsg->status & BM_DELETE) && !cl->nodelete)
continue;
nextisBID = 0;
firstIDline = 0;
/* copy the header */
while (size > 0 && fgets (line, LINELEN, cl->mfile) != NULLCHAR) {
kwait (NULL); /* can cause problems if exiting NOS */
#if 0
if (!firstIDline && nextisBID && (cp = strstr (line, "AA")) != NULLCHAR) {
/*what follows is the message-number*/
msgid = atol (cp + 2);
#else
if (!firstIDline && nextisBID && strstr (line, "AA") != NULLCHAR) {
#endif
nextisBID = 0;
firstIDline = 1;
}
if (!strncmp (line, Hdrs[RECEIVED], strlen (Hdrs[RECEIVED])))
nextisBID = 1;
if (!strncmp (line, Hdrs[STATUS], strlen (Hdrs[STATUS])))
foundstatus = 1;
size -= (long) strlen (line);
if (*line == '\n') {
#ifdef notagain
if (cmsg->status & BM_FORWARDED) {
fprintf (nfile, "%s%s\n", Hdrs[XFORWARD],
cl->name);
diff += (strlen (Hdrs[XFORWARD]) + strlen (cl->name) + 1);
}
#endif
if (!foundstatus && (cmsg->status & BM_READ) != 0 && !cl->nostatus) {
fprintf (nfile, "%sR\n", Hdrs[STATUS]);
diff += (long) (strlen (Hdrs[STATUS]) + 2);
}
fprintf (nfile, "\n");
break;
}
fputs (line, nfile);
kwait (NULL); /* can cause problems if exiting NOS */
}
kwait (NULL);
while (size > 0 && fgets (line, LINELEN, cl->mfile) != NULLCHAR) {
kwait (NULL); /* can cause problems if exiting NOS */
if (!cl->nostatus && !strncmp (line, Hdrs[RRECEIPT], strlen (Hdrs[RRECEIPT]))
&& !strcmp (cl->name, cl->area) && (cmsg->status & BM_RRECEIPT)) {
fputs ("Return-Receipt-Sent\n", nfile);
diff -= (long) strlen (line);
diff += 20;
} else
fputs (line, nfile);
size -= (long) strlen (line);
kwait (NULL); /* dont want no damaged files */
if (ferror (nfile)) {
(void) fclose (nfile);
(void) fclose (cl->mfile);
rmlock (Mailspool, cl->area);
free (cl);
return;
}
}
cmsg->status &= BM_READ;
cmsg->size += diff;
updateCtl (cl->area, cmsg);
(void) fflush (nfile);
numwritten++;
}
if (!cl->isbbs && !stricmp (cl->name, cl->area))
*cl->hostsize = ftell (nfile); /* Update the size of our hosts' mailbox */
/* potientially dangerous! */
/* remove a zero length file */
if (!numwritten) {
(void) fclose (nfile);
(void) unlink (buf);
} else
(void) fclose (nfile);
(void) fclose (cl->mfile);
(void) remove (buf2); /* leave it around, for now! NOT! */
rmlock (Mailspool, cl->area);
free (cl->mbox);
free (cl);
kwait (NULL);
return;
}
/* close the temp file while coping mail back to the mailbox */
int
closenotes (struct mbx *m, int exiting)
{
int nostatus, nodelete = 0;
struct clparms *cl;
if (m->mfile == NULLFILE || !*m->area)
return 0;
nostatus = issysarea (m->area);
/* Allow any user to delete from area names starting with 'nts' */
if (!strnicmp (m->area, "nts", 3))
nostatus = 0;
if (!(m->change & CHG_NORMAL) || nostatus) { /* no changes were made (or bulletin) */
mfclose (m);
m->mboxsize = 0;
return 0;
}
/* If this area is not our own private message area, then we will not add a
* Status line to indicate that the message has been read.
*/
if (strcmp (m->area, m->name)) {
nostatus = 1;
/* Don't delete messages from public message areas unless you are
* a SYSOP.
*/
nodelete = !(m->privs & SYSOP_CMD);
}
/* Allow any user to delete from area names starting with 'nts' */
if (!strnicmp (m->area, "nts", 3))
nodelete = 0;
/* If not a SYSOP, not an "nts" area, not our area, AND deletions, must be BBS forward */
if (m->change & CHG_DELETE) {
nodelete = 0;
log (-1, "PBBS forwarding rewrite of personal area '%s' by %s ", m->area, m->name);
}
if (nostatus && nodelete) {
mfclose (m);
m->mboxsize = 0;
return 0;
}
scanmail (m);
if (lockit (m))
return -1;
cl = (struct clparms *) mallocw (sizeof (struct clparms));
cl->nodelete = nodelete;
cl->nostatus = nostatus;
if (!exiting)
cl->hostsize = &m->mysize;
else {
cl->_hostsize = m->mysize;
cl->hostsize = &cl->_hostsize;
}
cl->isbbs = (m->sid & MBX_SID);
strncpy (cl->name, m->name, 20);
strncpy (cl->area, m->area, 64);
cl->mfile = m->mfile;
cl->nmsgs = m->nmsgs;
cl->mbox = m->mbox;
(void) newproc ("Closing notefile", 2560, close_notes, 0, cl, 0, 0);
kwait (NULL);
m->mfile = NULLFILE;
m->mbox = (struct let *) 0;
mfclose (m);
m->mboxsize = 0;
return 0;
}
#endif /* MAILCMDS */
/* Returns 1 if name is in the given area file, 0 otherwise */
static int
is_area (const char *name, const char *listfile)
{
char buf[LINELEN], *cp;
FILE *fp;
if ((fp = fopen (listfile, READ_TEXT)) == NULLFILE)
return 0;
while (fgets (buf, sizeof (buf), fp) != NULLCHAR) {
/* The first word on each line is all that matters */
if (isalnum (buf[0])) { /* skip comments */
if ((cp = strpbrk (buf, " \t\n")) != NULLCHAR)
*cp = '\0';
(void) nntp_name_expansion (buf);
if (stricmp (name, buf) == 0) { /* found it */
(void) fclose (fp);
return 1;
}
}
}
(void) fclose (fp);
return 0;
}
/* Returns 1 if name is a public message Area, 0 otherwise */
int
isarea (const char *name)
{
return (is_area2 (name));
}
/* Returns 1 if name is a public message Area, 0 otherwise */
int
issysarea (const char *name)
{
return (is_area (name, AreaSlist));
}
#ifdef MAILCMDS
int
lockit (struct mbx *m)
{
int c, cnt = 0;
while (mlock (Mailspool, m->area)) {
(void) kpause (1000L); /* Wait one second */
if (++cnt == 10) {
char buf[80];
sprintf (buf, "Mail file '%s' is busy, Abort or *Retry ? ", m->area);
cnt = 0;
c = tkeywait (buf, 1, m->linemode);
if (c == 'A' || c == 'a' || c == EOF) {
mfclose (m);
return 1;
}
}
}
return 0;
}
/* read the next message or the current one if new */
int
doreadnext (int argc OPTIONAL, char *argv[]OPTIONAL, void *p)
{
struct mbx *m;
char buf[14], *newargv[2], buf2[6];
m = (struct mbx *) p;
if (m->mfile == NULLFILE)
return 0;
if ((m->mbox[m->current].status & BM_READ) != 0) {
if (m->current == 1 && m->anyread == 0)
;
else if (m->current < m->nmsgs)
m->current++;
else {
tputs ("Last message\n");
return 0;
}
}
sprintf (buf, "%d", m->current);
strcpy (buf2, "read");
newargv[0] = buf2;
newargv[1] = buf;
return doreadmsg (2, newargv, p);
}
#endif
#ifdef SAMCALLB
void
leadingCaps (char *str, int others)
{
char *cp;
cp = str;
(void) strlwr (cp);
if (!others) {
if ((cp = strchr (cp, ' ')) != 0)
(void) strupr (cp);
return;
}
do {
cp = strchr (cp, ' ');
if (cp != NULL) {
cp = skipwhite (cp);
*cp = (char) toupper (*cp);
}
} while (cp);
}
#endif
char *
mblookname (struct mbx *m, char *str)
{
if ((m != NULLMBX) && (m->realname) && (*m->realname == '(') && (m->realname[1] != ')'))
return (strdup (m->realname));
if (strchr (str, '('))
return (0); /* already has a name */
#ifdef SAMCALLB
return (cb_lookname (str));
#else
return (0);
#endif
}
#ifdef MAILCMDS
extern int MbRead;
/* display message on the crt given msg number */
/* Modified to allow the 'RM' command, 920307 - WG7J */
int
doreadmsg (int argc, char *argv[], void *p)
{
struct mbx *m;
register int c, col, lin;
unsigned char buf[MAXBUF + 2], *cp, *cp2;
char *subj = 0, *theto = 0;
int msg, cnt, i, usemore = 0, verbose, mbxheader, pathcol = 5;
int header, lastheader;
long size;
char *myargv[NARG];
int myargc;
int maxmsg;
struct let *cmsg;
char *tmpbuf;
char *returnreceipt;
#ifdef USERLOG
long msgid;
#endif
m = (struct mbx *) p;
/*Check for read-permissions - WG7J */
if (m->privs & NO_READCMD) {
tputs (Noperm);
return 0;
}
#ifdef MBFWD
if (m->stype == 'O')
return (dombroute (argc, argv, p));
#endif
if ((m->mfile == NULLFILE) || (m->nmsgs == 0)) {
if (!(m->privs & ALL_AREAS))
tputs (Nomail);
return 0;
}
if ((lin = m->morerows) != 0)
usemore = 1; /* Display More prompt */
/*If this is the RM or VM command, setup myargv[]
*to contain up to NARG message numbers - WG7J
*/
if (m->stype == 'M') {
myargc = 1;
if (!m->newmsgs) {
tputs (Nomail);
return 0;
}
/* scan all messsages to find unread ones */
maxmsg = min (m->nmsgs, m->current + NARG - 2);
for (i = m->current; i <= maxmsg; i++) {
cmsg = &m->mbox[i];
if (!(cmsg->status & BM_READ)) { /*found an unread msg!*/
tmpbuf = mallocw (18); /*allocate space for the new argument*/
myargv[myargc++] = itoa (i, tmpbuf, 10);
}
}
argc = myargc;
} else {
/*simply point to the old arguments*/
for (i = 1; i < argc; i++)
myargv[i] = argv[i];
}
if (argc == 1) {
tputs ("Usage: Read/Verbose #\n");
return 0;
}
m->state = MBX_READ;
for (i = 1; i < argc; ++i) {
msg = atoi (myargv[i]); /*lint !e644 */
if (msg < 1 || msg > m->nmsgs) {
if (!(m->privs & ALL_AREAS))
tprintf (Badmsg, msg);
goto iamdone;
}
MbRead++;
fseek (m->mfile, m->mbox[msg].start, 0);
#ifdef USERLOG
/* Check the ID number of this message and
* adjust new lastread count, if needed - WG7J
*/
(void) fgets ((char *) buf, MAXBUF + 2, m->mfile); /* the 'From ' line */
(void) fgets ((char *) buf, MAXBUF + 2, m->mfile); /* the 'Received: ' line */
(void) fgets ((char *) buf, MAXBUF + 2, m->mfile); /* the ' ID' line */
/* find id number */
if ((cp = (unsigned char *) strstr ((char *) buf, "AA")) != (unsigned char *) 0) {
/*what follows is the message-number*/
msgid = atol ((char *) cp + 2);
if ((msgid > m->lastread) && (msgid > m->newlastread))
m->newlastread = msgid;
}
fseek (m->mfile, m->mbox[msg].start, 0);
#endif
#ifdef nope /* was USERLOG */
if ((m->mbox[msg].bid > m->lastread) && (m->mbox[msg].bid > m->newlastread))
m->newlastread = m->mbox[msg].bid;
#endif
m->anyread = 1;
returnreceipt = 0;
size = m->mbox[msg].size;
m->current = msg;
header = NOHEADER;
mbxheader = 0;
if ((*argv[0] == 'v') || (m->stype == 'H'))
verbose = 1; /* display all header lines */
else
verbose = 0;
m->inmessage = 1;
if (m->stype != 'M')
bbscolorcls (m);
bbscolorchange (m, "07");
if (m->sid & MBX_HTTP)
tprintf ("<PRE>\n");
tprintf ("Message #%d %s\n", msg,
m->mbox[msg].status & BM_ONHOLD ? "[On Hold - Awaiting Review of SYSOP]" :
m->mbox[msg].status & BM_DELETE ? "[Deleted]" : "");
if ((m->mbox[msg].status & (BM_ONHOLD | BM_DELETE)) && !(m->privs & SYSOP_CMD))
continue;
/* When you have sysop privs,
* only mark your own private area as read and changed.
* other areas, only mark as read, NOT changed !
* for regular users, simply mark all as read and changed.
* That way sysops can read other's mail without
* marking stuff read that really wasn't read by
* the right person !
* for regular users, simply mark as read.
* 910312 - WG7J
*/
if (!(m->mbox[msg].status & BM_READ)) {
m->mbox[msg].status |= BM_READ;
/* regular users */
if (!issysarea (m->area) && (!(m->privs & SYSOP_CMD) || ((m->privs & SYSOP_CMD) && !strcmp (m->name, m->area)))) /*sysops*/
m->change |= CHG_READ;
m->newmsgs--;
}
--lin;
col = 0;
while (!feof (m->mfile) && size > 0) {
for (col = 0; col < MAXBUF;) {
c = getc (m->mfile);
size--;
if (feof (m->mfile) || size == 0) /* end this line */
break;
if (c == '\t') {
cnt = col + 8 - (col & 7);
if (cnt >= MAXBUF) /* end this line */
break;
while (col < cnt)
buf[col++] = ' ';
} else {
if (c == '\n')
break;
buf[col++] = uchar (c);
}
}
if (col < MAXBUF)
buf[col++] = '\n';
buf[col] = '\0';
if (mbxheader > 0) {
/* Digest R: lines and display as a Path: line */
if (strnicmp ((char *) buf, "R:", 2) != 0 || (cp = (unsigned char *) strchr ((char *) buf, '@')) == (unsigned char *) 0) {
tputc ('\n');
bbscolorchange (m, "0B");
mbxheader = -1; /* don't get here again */
verbose = 1;
} else {
if (*(++cp) == ':')
++cp;
for (cp2 = cp; isalnum (*cp2); ++cp2)
;
*cp2 = '\0';
if (mbxheader++ == 1) {
bbscolorchange (m, "07");
tputs (Hdrs[PATH]);
pathcol = 5;
--lin;
} else {
tputc ('!');
if (++pathcol + (int) strlen ((char *) cp) > MAXCOL - 3) {
tputs ("\n ");
pathcol = 5;
--lin;
}
}
tputs ((char *) cp);
pathcol += (int) strlen ((char *) cp);
++lin; /* to allow for not printing it later */
}
}
if (col == 1 && !mbxheader) {
bbscolorchange (m, "0B");
/* last header line reached */
if (!verbose)
mbxheader = 1;
}
if (verbose)
/* tputs (buf); */
(void) colorprintf (NULLCHAR, m->usecolor, buf);
if (!strncmp (Hdrs[RRECEIPT], (char *) buf, strlen (Hdrs[RRECEIPT])))
returnreceipt = strdup ((char *) &buf[strlen (Hdrs[RRECEIPT])]);
if (!verbose && !mbxheader) {
lastheader = header;
if (!isspace (*buf))
header = htype ((char *) buf);
else
header = lastheader;
switch (header) {
case SUBJECT:
subj = strdup ((char *) &buf[strlen (Hdrs[SUBJECT]) - 4]);
tputs ((char *) buf);
break;
case MSGID:
#ifdef MBFWD
/* give a "traditional BBS" version to the user */
{
char bid[LINELEN];
(void) makeBBSbid (bid, sizeof (bid), (char *) buf);
(void) strupr (bid);
tprintf ("%s%s\n", Hdrs[MSGID], bid);
}
break;
#endif
case TO:
theto = strdup ((char *) &buf[strlen (Hdrs[TO])]);
/* fall through */
case FROM:
{
char *nm;
rip ((char *) buf);
tputs ((char *) buf);
nm = strchr ((char *) buf, ' ');
if (nm && (nm = mblookname (NULLMBX, ++nm)) != 0) {
tputs (nm);
free (nm);
}
tputc ('\n');
}
break;
case CC:
case DATE:
case REPLYTO:
case APPARTO:
case ERRORSTO:
case XMAILGROUP:
case ORGANIZATION:
tputs ((char *) buf);
break;
case XBBSHOLD:
if (m->privs & SYSOP_CMD)
tputs ((char *) buf);
break;
default:
++lin;
}
}
col = 0;
if (usemore && --lin <= 0) {
if (m->type == TELNET || m->type == TIP)
c = tkeywait ("--More--", 0, m->linemode);
else /* For AX.25 and NET/ROM connects - WG7J */
c = mykeywait (anymore, m);
#ifdef MBXTDISC
start_timer (&m->tdisc);
#endif
lin = m->morerows;
if (c == -1 || c == 'q' || c == 'Q')
break;
#ifdef TNOS_68K
if (c == '\l' || c == '\r')
#else
if (c == '\n' || c == '\r')
#endif
lin = 1;
}
} /* while !eof */
#ifdef TUTOR
{
char savbuf[MBXLINE + 1];
memcpy (savbuf, m->line, MBXLINE + 1);
sprintf (m->line, "msgend %d", msg);
mbscripthook (m, "msgend.sys");
memcpy (m->line, savbuf, MBXLINE + 1);
}
#endif
if (returnreceipt && !MBnoReturnReceipt && !(m->mbox[msg].status & BM_RRECEIPT)) {
struct mbx *mm;
m->mbox[msg].status |= BM_RRECEIPT;
rip (returnreceipt); /* strip off <CR> */
tprintf ("[Sending return receipt to '%s']\n", returnreceipt);
mm = (struct mbx *) mallocw (sizeof (struct mbx));
mm->tomsgid = mm->date = mm->origbbs = mm->tofrom = NULLCHAR;
mm->origto = returnreceipt;
if (!subj)
subj = strdup (" No subject");
mm->subject = subj;
mm->realname = strdup ("()");
rip (subj); /* strip off <CR> */
subj[0] = subj[1] = 'R';
subj[2] = ':';
subj[3] = ' ';
mm->stype = 'P';
strncpy (mm->name, m->name, 20);
if ((mm->tfile = tmpfile ()) != NULLFILE) {
struct list *cclist = NULLLIST;
char fullfrom[MBXLINE];
(void) addlist (&cclist, returnreceipt, 0, returnreceipt);
sprintf (fullfrom, "%s@%s", m->name, Hostname);
(void) mbx_data (mm, NULLLIST, NULLCHAR, 0);
if (!theto)
theto = strdup ("unknown addressee");
rip (theto); /* strip off the <CR> */
fprintf (mm->tfile, "Message received - Originally addressed to: '%s'\n", theto);
fseek (mm->tfile, 0L, 0); /* rewind file */
(void) queuejob (mm->tfile, Hostname, cclist, fullfrom);
(void) fclose (mm->tfile);
del_list (cclist);
smtptick (NULL); /* wake up SMTP to send mail */
}
free (mm->realname);
free (mm);
free (returnreceipt);
}
free (subj);
free (theto);
m->inmessage = 0;
#ifdef STATS_AREA
STATS_addarea (1, 1, m->area);
#endif
} /* for argc */
iamdone:
/* If this was 'RM' or 'VM',
* free the memory allocated for myargv[] - WG7J
*/
if (m->stype == 'M') {
for (i = 1; i < argc; i++)
free (myargv[i]);
}
if (m->sid & MBX_HTTP)
tprintf ("</PRE>\n");
return 0;
}
/* Set up m->to when replying to a message. The subject is returned in
* m->line.
*/
int
mbx_reply (
int argc,
char *argv[],
struct mbx *m,
struct list **cclist, /* Pointer to buffer for pointers to cc recipients */
char **rhdr /* Pointer to buffer for extra reply headers */
) {
char subject[MBXLINE], *msgid = NULLCHAR, *date = NULLCHAR;
char *cp;
int msg, lastheader, header = NOHEADER, k;
long size;
/* Free anything that might be allocated
* since the last call to mbx_to() or mbx_reply()
*/
free (m->to);
m->to = NULLCHAR;
free (m->tofrom);
m->tofrom = NULLCHAR;
free (m->tomsgid);
m->tomsgid = NULLCHAR;
free (m->origto);
m->origto = NULLCHAR;
subject[0] = '\0';
if (argc == 1)
msg = m->current;
else
msg = atoi (argv[1]);
if (m->mfile == NULLFILE) {
if (m->sid & MBX_SID)
tputs ("NO - ");
tputs (Nomail);
return 0;
}
if (msg < 1 || msg > m->nmsgs) {
if (m->sid & MBX_SID)
tputs ("NO - ");
tprintf (Badmsg, msg);
return -1;
}
fseek (m->mfile, m->mbox[msg].start, 0);
size = m->mbox[msg].size;
m->current = msg;
while (size > 0 && fgets (m->line, MBXLINE - 1, m->mfile) != NULLCHAR) {
size -= (long) strlen (m->line);
if (m->line[0] == '\n') /* end of header */
break;
rip (m->line);
lastheader = header;
if (!isspace (m->line[0])) {
header = htype (m->line);
lastheader = NOHEADER;
}
switch (header) {
case SUBJECT:
trimright (m->line);
if (strlen (m->line) > 11 && !strnicmp (&m->line[9], "Re:", 3))
strncpy (subject, &m->line[9], MBXLINE);
else {
strcpy (subject, "Re: ");
strncpy (&subject[4], &m->line[9], MBXLINE - 4);
}
break;
case FROM:
trimright (m->line);
if (m->to == NULLCHAR && (cp = getaddress (m->line, 0)) !=
NULLCHAR)
m->to = strdup (cp);
break;
case REPLYTO:
if ((cp = getaddress (m->line, 0)) != NULLCHAR) {
free (m->to);
m->to = strdup (cp);
}
break;
case MSGID:
trimright (m->line);
free (msgid);
msgid = strdup (&m->line[12]);
break;
case DATE:
free (date);
date = strdup (&m->line[6]);
break;
#ifdef notdef
/* don't want a reply back to myself - WG7J */
case TO:
case APPARTO:
#endif
case CC:
/* Get addresses on To, Cc and Apparently-To lines */
cp = m->line;
k = (int) (strlen (cp) + 1);
m->line[min(k, MBXLINE)] = '\0'; /* add extra null at end */
for (;;) {
if ((cp = getaddress (cp, lastheader == header || cp != m->line)) == NULLCHAR)
break;
(void) addlist (cclist, cp, 0, cp);
/* skip to next address, if any */
cp += strlen (cp) + 1;
}
break;
default:
break;
}
}
if (msgid != NULLCHAR || date != NULLCHAR) {
*rhdr = mallocw (LINELEN);
sprintf (*rhdr, "In-Reply-To: your message ");
if (date != NULLCHAR) {
sprintf (m->line, "of %s.\n", date);
strcat (*rhdr, m->line);
if (msgid != NULLCHAR)
strcat (*rhdr, " ");
}
if (msgid != NULLCHAR) {
sprintf (m->line, "%s\n", msgid);
strcat (*rhdr, m->line);
}
free (msgid);
free (date);
}
strncpy (m->line, subject, MBXLINE);
return 0;
}
#ifdef USERLOG
/*get the last message listed/read
*from the areaname.USR file
*keeps track for each user.
*February '92, WG7J
*/
void
getlastread (struct mbx *m)
{
FILE *Alog;
char buf[256];
char *cp;
int found = 0;
m->lastread = m->newlastread = 0L;
sprintf (buf, "%s/users/%s.usr", Mailspool, m->area);
if ((Alog = subdir_fopen (buf, "r+")) == NULLFILE) {
/* USR file doesn't exist, create it */
if ((Alog = subdir_fopen (buf, "w")) == NULLFILE)
return;
/* Add this user as first one */
sprintf (buf, "%s 0\n", m->name);
fputs (buf, Alog);
(void) fclose (Alog);
return;
}
/*Find user in the usr file for this area*/
for (;;) {
if (fgets (buf, sizeof (buf), Alog) == NULLCHAR)
break;
if ((cp = strchr (buf, ' ')) != NULLCHAR) {
*cp = '\0';
if (!stricmp (m->name, buf)) {
/*found user*/
cp++;
while (*cp == ' ') /*skip blanks*/
cp++;
m->lastread = atol (cp);
found = 1;
break;
}
}
}
if (!found) {
/*Add user*/
sprintf (buf, "%s 0\n", m->name);
fputs (buf, Alog);
}
(void) fclose (Alog);
return;
}
/* Write the new last read id number to the USR file - WG7J
* only update if this is not a bbs,
* current area is a public area and not 'help',
* or anything that starts with 'sys',
* and a new message was actually listed/read
*/
void
setlastread (struct mbx *m)
{
FILE *Alog, *tfile;
char buf[256];
char tmpname[80];
char *cp;
int doit = 0;
if ((m->sid & MBX_SID) || (m->newlastread <= m->lastread))
return;
/* if(issysarea(m->area))
if ((m->privs & MBX_SYSOP) || (stricmp(m->area, "help")))
doit = 1; */
if (isarea (m->area) && strcmp (m->area, "help"))
doit = 1;
if ((m->privs & SYSOP_CMD) && issysarea (m->area))
doit = 1;
if (doit) {
#ifdef notdef
tprintf ("SETLAST: %d\n", m->newlastread);
#endif
sprintf (buf, "%s/users/%s.usr", Mailspool, m->area);
/* Rename the USR file to a tempfile */
#ifdef UNIX
strncpy (tmpname, buf, 75);
strcat (tmpname, ".bak");
#else
(void) tmpnam (tmpname);
#endif
if (rename (buf, tmpname))
/* Can't rename ??? */
return;
if ((Alog = subdir_fopen (buf, "w")) == NULLFILE) {
/* can't creat new USR file ???*/
(void) rename (tmpname, buf); /* try to undo the damage */
return;
}
if ((tfile = subdir_fopen (tmpname, "r")) == NULLFILE)
/* can't open renamed file ??? */
return;
/*Write all users back, but update this one!*/
while (fgets (buf, sizeof (buf), tfile) != NULLCHAR) {
if ((cp = strchr (buf, ' ')) != NULLCHAR)
*cp = '\0';
if (!stricmp (m->name, buf)) {
/*found this user*/
sprintf (buf, "%s %lu\n", m->name, m->newlastread);
} else if (cp)
*cp = ' '; /* restore the space !*/
fputs (buf, Alog);
}
(void) fclose (tfile);
unlink (tmpname);
(void) fclose (Alog);
}
return;
}
#endif /*USERLOG*/
void
scanmail (struct mbx *m)
{ /* Get any new mail */
if (!isnewmail (m))
return;
if (lockit (m))
return;
(void) initnotes (m);
rmlock (Mailspool, m->area);
}
/* Check the current mailbox to see if new mail has arrived.
* Returns the difference in size.
*/
static long
isnewmail (struct mbx *m)
{
char buf[256];
sprintf (buf, "%s/%s.txt", Mailspool, m->area);
return fsize (buf) - m->mboxsize;
}
/* Check if the private mail area has changed */
long
isnewprivmail (struct mbx *m, const char *ext)
{
long cnt;
char buf[256];
sprintf (buf, "%s/%s.%s", Mailspool, m->name, ext);
cnt = m->mysize;
m->mysize = fsize (buf);
return m->mysize - cnt; /* != 0 not more than once */
}
void
notifynewmail (struct mbx *m)
{ /* not a BBS, but from within ANY area */
if (!(m->sid & MBX_SID) && (isnewprivmail (m, "txt") > 0L)) {
tprintf ("\007You have new mail in your personal area (%s). Please Kill when read!\n", m->name);
usflush (Curproc->output);
}
}
#endif
#endif
/* This function returns the length of a file. The proper thing would be
* to use stat(), but it fails when using DesqView together with Turbo-C
* code.
*/
long
fsize (char *name)
{
long cnt;
FILE *fp;
if ((fp = subdir_fopen (name, READ_TEXT)) == NULLFILE)
return -1L;
fseek (fp, 0L, 2);
cnt = ftell (fp);
/* cnt = filelength (fileno(fp)); */
(void) fclose (fp);
return cnt;
}
#ifdef MAILCMDS
/* close the temporary mail file */
static void
mfclose (struct mbx *m)
{
if (m->mfile != NULLFILE)
(void) fclose (m->mfile);
m->mfile = NULLFILE;
#ifdef SETVBUF
free (m->stdoutbuf);
m->stdoutbuf = NULLCHAR;
#endif
}
#endif
/* erase a previous prompt via backspaces */
void
backEmUp (int len)
{
int i;
/* Get rid of the prompt */
for (i = len; i != 0; i--)
tputc ('\b');
for (i = len; i != 0; i--)
tputc (' ');
for (i = len; i != 0; i--)
tputc ('\b');
tflush ();
}
/* Print prompt and read one character, telnet version */
int
tkeywait (
const char *prompt, /* Optional prompt */
int flush, /* Flush queued input? */
int linemode /* Negotiate line mode? */
) {
int c, cl, oldimode, oldomode;
if (flush && socklen (Curproc->input, 0) != 0)
(void) recv_mbuf (Curproc->input, NULL, 0, NULLCHAR, 0); /* flush */
if (prompt == NULLCHAR)
prompt = hitEnter;
tprintf ("%s", prompt);
/* hack - handle Unix telnet clients correctly */
if (linemode)
tprintf ("%c%c%c%c%c%c%c", IAC, SB, TN_LINEMODE, 1, 2, IAC, SE);
tprintf ("%c%c%c", IAC, WILL, TN_ECHO);
usflush (Curproc->output);
/* discard the response */
oldimode = sockmode (Curproc->input, SOCK_BINARY);
oldomode = sockmode (Curproc->output, SOCK_BINARY);
while ((c = rrecvchar (Curproc->input)) == IAC) {
c = rrecvchar (Curproc->input);
if (c == SB) {
if ((c = rrecvchar (Curproc->input)) == EOF)
break;
cl = c;
c = rrecvchar (Curproc->input);
while ((c != EOF) && !(cl == IAC && c == SE)) {
cl = c;
c = rrecvchar (Curproc->input);
}
} else if (c > 250 && c < 255)
(void) rrecvchar (Curproc->input);
}
(void) sockmode (Curproc->output, oldomode);
(void) sockmode (Curproc->input, oldimode);
backEmUp ((int) strlen (prompt));
tprintf ("%c%c%c", IAC, WONT, TN_ECHO);
if (linemode)
tprintf ("%c%c%c%c%c%c%c", IAC, SB, TN_LINEMODE, 1, 1, IAC, SE);
usflush (Curproc->output);
return c;
}
/* Print -more- prompt and read reply,
* AX.25 and NETROM version - WG7J
* <CR> is taken as a 'Yes'
*/
int
mykeywait (char *prompt, struct mbx *m)
{
tputs (prompt);
usflush (Curproc->output);
if (recvline (m->user, (unsigned char *) m->line, MBXLINE) == -1) {
return -1;
}
/* Only 'N' or 'n' really matters */
if ((*m->line == 'N') || (*m->line == 'n'))
return -1;
return 0;
}
struct areas {
struct areas *next;
char *name;
};
static struct areas *Areas = NULL;
static void
readareas (const char *name)
{
FILE *fp;
struct areas *ca = (struct areas *) 0, *na;
char *cp, buf[FILE_PATH_SIZE];
if ((fp = fopen (name, READ_TEXT)) == NULL)
return;
while (fgets (buf, sizeof (buf), fp) != NULL) {
if (buf[0] == '#' || buf[0] == '-') /* comment line */
continue;
cp = buf;
/* get first token on line */
while (*cp) {
if (*cp == '\n' || *cp == ' ' || *cp == '\t') {
*cp = '\0';
break;
}
cp++;
}
if (*buf) {
na = (struct areas *) mallocw (sizeof (struct areas));
na->name = strdup (buf);
na->next = NULL;
if (Areas == NULL)
Areas = na;
else if (ca)
ca->next = na;
ca = na;
}
}
(void) fclose (fp);
}
static int
is_area2 (const char *name)
{
#ifdef MAILCMDS
struct areas *a;
if (!Areas)
readareas (Arealist);
a = Areas;
while (a) {
if (stricmp (a->name, name) == 0)
return 1;
a = a->next;
}
#endif
return 0;
}
void
freeareas (void)
{
struct areas *a;
while (Areas) {
a = Areas;
Areas = Areas->next;
if (a->name) /* should always be, but just in case */
free (a->name);
free (a);
}
}